Queue-based technology is an underrepresented but
powerful way to exchange data and events between disconnected clients.
WCF has full support for Microsoft's queuing implementation (MSMQ) and
BizTalk has an adapter specifically targeted at the netMsmqBinding WCF binding.
Why introduce yet another
layer in your service communication? BizTalk has queuing logic, so
what benefit do we get by having our service client send a message to an
external queue that BizTalk acts upon? First of all, you get delivery
assurance in the case of the service being offline. As you are not
travelling over an inherently unreliable transport like HTTP, you can be
confident that your message will arrive only once at its destination
because of the intermediary queue. Also, a queue enables you to
implement a level of soft throttling by allowing the queue to get
pummeled by inbound requests but allow the service to process them at
its leisure.
What we will
demonstrate here is how to put MSMQ on both ends of a BizTalk solution.
That is, the client application calls a BizTalk WCF endpoint that uses
MSMQ as its transport, and when processing is complete, BizTalk sends
its concluding message to a service over a MSMQ channel.
As with all other WCF
bindings, the developer's interactions with MSMQ are fairly transparent
and do not actively impact the client code. A developer does not need to
understand any of the plumbing behind MSMQ and only need to flip the
appropriate binding switches to use the queuing transport.
Before building any BizTalk
bits, how about we create the actual queues that our solution will use.
To access the MSMQ panel in Windows Server 2008, we visit the Server Manager, expand the Features node, and highlight the Messaging Queuing
node. Here we can create two private transactional queues that will
house our information while in transit between client and service.
Now we erect the
terminating service, which publishes a final acknowledgement message to a
dedicated queue. For our scenario, we have a customer satisfaction
system that is interested in knowing when adverse events have been
resolved. This system wants to send surveys to those who have interacted
with our company and gauge their opinions of our efficiency. The first
step to building our service requires building our interface contract.
We will keep it fairly simple.
[ServiceContract(Namespace = "http://Seroter.BizTalkSOA.Chapter6")]
public interface ISatisfactionSystem
{
[OperationContract(IsOneWay = true)]
void ProcessClosedAE(ClosedAE closedAE);
}
[DataContract(Namespace = "http://Seroter.BizTalkSOA.Chapter6")]
public class ClosedAE
{
[DataMember]
public string AEID { get; set; }
[DataMember]
public string Product { get; set; }
[DataMember]
public string ResolutionDescription { get; set; }
[DataMember]
public DateTime CloseDate { get; set; }
}
I've highlighted the fact
that service operations used on MSMQ service endpoints must be
designated with a one-way messaging pattern. This is the rare example of
endpoint selection playing a primary role in contract design.
Critical point:
Earlier I mentioned that BizTalk Server 2009 does not support truly asynchronous services that have their IsOneWay flag set to true. That's not entirely true. WCF service contracts associated with the MSMQ transport require that the IsOneWay flag is equal to true,
and BizTalk readily supports that. Hence, unlike other WCF bindings,
the MSMQ binding requires you to be aware of which transport you are
planning to use when designing the contract.
Next, our contract needs to be
implemented by an actual service. In this case, our service will simply
write a notification in the machine's event log when a message has been
received from the queue.
class SatisfactionSystemService : ISatisfactionSystem
{
public void ProcessClosedAE(ClosedAE closedAE)
{
System.Diagnostics.EventLog.WriteEntry("Satisfaction System Service", "Adverse Event Closed Event Received for case " + closedAE.AEID);
}
}
Finally, we have to host
our service. In this case, we can once again exploit our existing WCF
Service project and add a new individual service (.svc file) to it.
After this is in place with the appropriate service directive, we simply
need to append a new service endpoint in our configuration file.